package com.bokey.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bokey.entity.Follow;
import com.bokey.entity.Node;
import com.bokey.entity.User;
import com.bokey.service.FollowService;
import com.bokey.service.NodeService;
import com.bokey.service.UserService;
import com.bokey.utils.R;


import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@CrossOrigin // 跨域解决
@RestController
@RequestMapping("/node")
public class NodeController {
    @Resource
    private NodeService nodeService;
    @Resource
    private UserService userService;
//    @Resource
//    private FollowService followService;
    @Resource
    private CollectController collectController;

    //笔记上传
    @RequestMapping("/upload")
    public Boolean handleFormUpload( Node node,
                                   @RequestParam(value="file") List<MultipartFile> uploadfile,
                                    @CookieValue(value="userId") Integer userId, // 获取Cookie中的userId
                                   HttpServletRequest request) {
        // 判断数据库中该用户是否有同名笔记
        if(findNodeByName(node.getNodename(), userId)) {
            return false;
        }
        //判断上传的文件是否存在
        if(!uploadfile.isEmpty() && uploadfile.size()>0) {
            for (MultipartFile file : uploadfile) {
                //设置文件的保存目录地址 upload/用户id/笔记类别/笔记语言
                String dirPath = request.getServletContext().getRealPath("/upload/" + userId + "/"  + node.getClassName() + "/" + node.getLanguage() + "/");
                File filePath = new File(dirPath);
                //若保存文件的地址不存在，则创建目录
                if(!filePath.exists()) {
                    filePath.mkdirs();
                }
                //定义上传的文件名
                String newFilename = node.getNodename() + ".md";
                //使用MultipartFile接口的方法完成文件上传到指定位置
                try {
                    file.transferTo(new File(dirPath + "\\" +  newFilename));
                    // System.out.println("上传文件所在位置:"+dirPath+"上传文件的文件名:"+newFilename);
                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
            }
            //文件上传成功，向数据库中存入笔记相关信息
            node.setUserId(userId);
            node.setTime(new Date());
            //2.将笔记名，用户id，笔记语言，笔记类型，笔记地址存入数据库
            return nodeService.save(node);
        }else {
            return false;
        }
    }

    //笔记更新
    @RequestMapping("/updateNode/{nodeId}")
    public Boolean updateNode(@RequestParam(value="file") List<MultipartFile> uploadfile,
                                @PathVariable Integer nodeId,
                              HttpServletRequest request) {
        // 获取笔记信息
        QueryWrapper<Node> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",nodeId);
        Node node = nodeService.getOne(queryWrapper);
        //判断上传的文件是否存在
        if(!uploadfile.isEmpty() && uploadfile.size()>0) {
            for (MultipartFile file : uploadfile) {
                // 得到该笔记的路径
                String dirPath = request.getServletContext().getRealPath("/upload/" + node.getUserId() + "/"  + node.getClassName() + "/" + node.getLanguage() + "/");
                // 删除原来的文件
                deleteMyNode(nodeId,request);
                // 定义上传的文件名
                String newFilename = node.getNodename() + ".md";
                //使用MultipartFile接口的方法完成文件上传到指定位置
                try {
                    file.transferTo(new File(dirPath + "\\" +  newFilename));
                    // System.out.println("上传文件所在位置:"+dirPath+"上传文件的文件名:"+newFilename);
                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
            }
            // 更改笔记的日期
            node.setTime(new Date());
            // 将更新的日期存入数据库
            return nodeService.save(node);
        }else {
            return false;
        }
    }

    // 通过userId判断该用户是否有名字为nodeName的笔记(同名笔记)，若该用户有同名笔记返回true，若没有同名笔记返回false
    @RequestMapping("/findNodeByName/{nodeName}/{userId}")
    public boolean findNodeByName(@PathVariable String nodeName,@PathVariable Integer userId){
        QueryWrapper<Node> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userId).eq("nodename",nodeName);
        Node node = nodeService.getOne(queryWrapper);
        if(node==null) {
            return false;
        }
        return true;
    }

    // 分页 通过userID查找笔记
    @RequestMapping("/findByUserId/{userId}/{currentPage}/{pageSize}")
    public R findNodeByUserId(@PathVariable Integer userId,@PathVariable Integer currentPage,@PathVariable Integer pageSize){
        QueryWrapper<Node> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userId);
        Page<Node> page = new Page<>(currentPage,pageSize);
        Page<Node> nodePage = nodeService.page(page, queryWrapper);
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("id",userId);
        User user = userService.getOne(userQueryWrapper);
        return R.ok().data("nodes",nodePage.getRecords()).data("user",user);
    }

    // 通过userId查找该用户的笔记数量
    @RequestMapping("/getUserNodeNumByUserId/{userId}")
    public long getUserNodeNumByUserId(@PathVariable Integer userId){
        QueryWrapper<Node> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userId);
        return nodeService.count(queryWrapper);
    }

    // 分页，查找最近的笔记
    @RequestMapping("/findLately/{userId}/{currentPage}/{pageSize}")
    public R findLately(@PathVariable Integer userId,@PathVariable Integer currentPage,@PathVariable Integer pageSize){
        Date date = new Date();
        date.setTime(date.getTime() - 604800000);
        QueryWrapper<Node> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userId)
                .gt("time",date)
                .orderByDesc("time");
        Page<Node> page = new Page<>(currentPage,pageSize);
        Page<Node> nodePage = nodeService.page(page, queryWrapper);
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("id",userId);
        User user = userService.getOne(userQueryWrapper);
        return R.ok().data("nodes",nodePage.getRecords()).data("user",user);
    }

    // 查找用户最近的5篇笔记通过userId
    @RequestMapping("/findLatelyForFive/{userId}")
    public R findLatelyForFive(@PathVariable Integer userId){
        QueryWrapper<Node> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userId).orderByDesc("popularity").last("limit 4");
        List<Node> nodes = nodeService.list(queryWrapper);
        return R.ok().data("nodes",nodes);
    }


    // 分页查询，在所有笔记中找10篇
    @RequestMapping("/find/{currentPage}/{pageSize}")
    public R findNode(@PathVariable Integer currentPage,@PathVariable Integer pageSize){
        // 配置页面，查找笔记
        Page<Node> page = new Page<>(currentPage,pageSize);
        Page<Node> nodePage = nodeService.page(page);
        // 准备用户列表
        List<String> userNames = new ArrayList<>();
        for (Node item: nodePage.getRecords()) {
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id",item.getUserId());
            User user = userService.getOne(queryWrapper);
            userNames.add(user.getUsername());
        }
        // 返回本页的数据
        return R.ok().data("nodes",nodePage.getRecords()).data("users",userNames);
    }
    // 分页查询，查询登录用户关注用户的作品，以时间降序
    @RequestMapping("/findFollowerNode/{currentPage}/{pageSize}/{userId}")
    public R findFollowerNode(@PathVariable Integer currentPage,@PathVariable Integer pageSize,@PathVariable Integer userId) {
        Page<Node> nodePage = new Page<>(currentPage,pageSize);
        IPage<Node> node = nodeService.findBeFollowerNodeByFollowerId(nodePage, userId);
        List<String> usernames = new ArrayList<>();
        for (Node item:node.getRecords()) {
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id",item.getUserId());
            User user = userService.getOne(queryWrapper);
            usernames.add(user.getUsername());
        }
        return R.ok().data("nodes",node.getRecords()).data("users",usernames);
    }



    // 分页查询
    @RequestMapping("/selectFind/{input}/{order}/{currentPage}/{pageSize}")
    public R selectNode(@PathVariable String input,@PathVariable String order,@PathVariable Integer currentPage,@PathVariable Integer pageSize,@RequestBody Node node) {
        QueryWrapper<Node> nodeQueryWrapper = new QueryWrapper<>();
        Page<Node> page = new Page<>(currentPage,pageSize);
        // 只有用户选择了筛选框的选项，才添加条件判断
        if (!input.equals("none")) nodeQueryWrapper.like("nodename",input); // 笔记标题中有相同
        if (node.getPopularity() != null) nodeQueryWrapper.ge("popularity",node.getPopularity()); // 人气大于等于
        if (!node.getClassName().equals("none")) nodeQueryWrapper.eq("class_name",node.getClassName()); // 类型等于
        if (!node.getLanguage().equals("none")) nodeQueryWrapper.eq("language",node.getLanguage()); // 语言等于
        if (!order.equals("none")) nodeQueryWrapper.orderByDesc(order); // 通过时间/人气 降序排序
        Page<Node> nodePage = nodeService.page(page, nodeQueryWrapper);
        // 查找作者名
        List<String> usernames = new ArrayList<>();
        for (Node item: nodePage.getRecords()) {
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id",item.getUserId());
            User user = userService.getOne(queryWrapper);
            usernames.add(user.getUsername());
        }
        return R.ok().data("nodes",nodePage.getRecords()).data("users",usernames);
    }

    // 读取文件方法
    public String readFile(String filePath){
        String content = new String();
        //1.创建FileReader对象
        FileReader fileReader = null;
        int readLen = 0;
        char[] buf = new char[8]; // 一次读8个字符
        try {
            fileReader = new FileReader(filePath);
            //循环读取使用read(buf),返回的是实际读取到的字符数
            //如果返回-1，说明到文件结束
            while ((readLen = fileReader.read(buf)) != -1){
                content += new String(buf,0,readLen);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println(content);
        return content;
    }
    // 得到笔记内容
    @RequestMapping("/getContent/{userId}")
    public String getContent(@PathVariable Integer userId,@RequestBody Node node,HttpServletRequest request){
        // 得到笔记地址
        String dirPath = request.getServletContext().getRealPath("/upload/" + userId + "/"  + node.getClassName() + "/" + node.getLanguage() + "/" + node.getNodename() + ".md");
        System.out.println("读取文件：" + dirPath);
        // 调用读取文件方法，读取笔记内容
        String content = readFile(dirPath);
        // 数据库中该笔记的人气+1
        node.setPopularity(node.getPopularity() + 1); // 人气+1
        UpdateWrapper<Node> updateWrapper = new UpdateWrapper<>();
        LambdaUpdateWrapper<Node> eq = updateWrapper.lambda().eq(Node::getId,node.getId());
        System.out.println("人气更新：" + nodeService.update(node,eq));
        return content;
    }

    //笔记下载
    @RequestMapping("/download/{userId}/{className}/{language}/{nodename}")
    public ResponseEntity<byte[]> downloadTry(@PathVariable String userId,@PathVariable String className,@PathVariable String language,@PathVariable String nodename,
                                              HttpServletRequest request) throws Exception{
        //指定要下载的文件的所在路径:/upload/作者id/笔记类型/笔记语言
        String path = request.getServletContext().getRealPath("/upload/" + userId + "/" + className + "/" + language + "/" );
        System.out.println("下载路径："+path);
        String nodeName = nodename + ".md";
        System.out.println("文件名："+ nodeName);
        //创建文件对象
        File file = new File(path+File.separator+nodeName);
        //对文件名编码，防止中文乱码
        String filename = this.getFilename(request,nodeName);
        //设置响应头
        HttpHeaders headers = new HttpHeaders();
        //通知浏览器以下载的形式打开文件
        headers.setContentDispositionFormData("attachment", filename);
        //定义以流的形式下载返回文件数据
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        // 使用springMVC框架的ResponseEntity对象封装返回下载的文件数据
        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers, HttpStatus.OK);
    }
    //根据浏览器的不同进行编码设置，返回编码后的文件名
    private String getFilename(HttpServletRequest request, String filename)throws Exception{
        //IE不同版本User-Agent出现的关键词
        String[] IEBrowserKeyWords = {"MSIE","Trident","Edge"};
        //获取请求头代理信息
        String userAgent = request.getHeader("User-Agent");
        for(String keyWord : IEBrowserKeyWords) {
            if(userAgent.contains(keyWord)) {
                //IE内核浏览器，统一为UTF-8编码
                return URLEncoder.encode(filename,"UTF-8");
            }
        }
        //火狐等其他浏览器统一为ISO-8859-1编码显示
        return new String(filename.getBytes("UTF-8"),"ISO-8859-1");
    }

    // 删除笔记
    @RequestMapping("/deleteMyNode/{nodeId}")
    public int deleteMyNode(@PathVariable Integer nodeId,
                            HttpServletRequest request){
        QueryWrapper<Node> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",nodeId);
        Node node = nodeService.getOne(queryWrapper);
        //文件删除
        String[] path = { node.getNodename() + ".md"};
        String dir = request.getServletContext().getRealPath("/upload/" + node.getUserId() + "/" + node.getClassName() + "/" + node.getLanguage() + "/");
        if(delete(path,dir)){
            // 数据删除
            nodeService.remove(queryWrapper);
            // 删除该笔记的所有收藏
            collectController.deleteNodeCollect(nodeId);
            return 1;
        }else{
            return 0;
        }

    }
    // 从Tomcat服务器删除文件
    public boolean delete(String[] pathArr,String dir) {
        int len = pathArr.length;
        int count = 0;
        for (String path : pathArr) {
            //拼接文件完整路径
            String abpath = dir+ File.separator + path;
            //获取需要删除的文件
            File deleteFile = new File(abpath);
            if (deleteFile.exists() && deleteFile.isFile() && deleteFile.delete() == true) {
                count++;
            }
        }
        return count==len ? true:false;
    }

    // 修改笔记描述
    @RequestMapping("/updateDescription")
    public boolean updateDescription(@RequestBody Node node){
        QueryWrapper<Node> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",node.getId());
        // 查找出该id的笔记的所有信息
        Node nodeData = nodeService.getOne(queryWrapper);
        // 更新描述信息
        nodeData.setDescription(node.getDescription());
        // 存入数据库
        return nodeService.update(nodeData,queryWrapper);
    }

    // 修改笔记名称
    @RequestMapping("/updateNodename")
    public boolean updateNodename(@RequestBody Node node,HttpServletRequest request){
        QueryWrapper<Node> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",node.getId());
        // 查找出该id的笔记的所有信息
        Node nodeData = nodeService.getOne(queryWrapper);
        // 得到该笔记的路径
        String Path = request.getServletContext().getRealPath("/upload/"+ nodeData.getUserId() + "/" + nodeData.getClassName() + "/" + nodeData.getLanguage() + "/" + nodeData.getNodename() + ".md");
        try {
            // 修改文件名
            rename(Path,node.getNodename() + ".md");
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 更新笔记名信息
        nodeData.setNodename(node.getNodename());
        // 数据库更改数据
        return nodeService.update(nodeData,queryWrapper);
    }
    // 修改文件名
    public String rename(String path/*原文件路径+文件名*/,String newname/*要修改成的文件名*/) throws IOException {
        File oldFile = new File(path);
        if(!oldFile.exists())
        {
            return" no";//如果原文件不存在,返回no
        }
        System.out.println("原文件名称："+oldFile.getName());
        String rootPath = oldFile.getParent();
        System.out.println("根路径是："+rootPath);
        File newFile = new File(rootPath + File.separator + newname);
        System.out.println("修改后文件名称是："+newFile.getName());
        if (oldFile.renameTo(newFile))
        {
            System.out.println("修改成功!");
            return "ok";
        }
        else
        {
            System.out.println("修改失败");
            return" no";
        }
    }


    @RequestMapping("/alter/{item}/{value}/{nodeId}")
    // 修改笔记的笔记类型或笔记语言
    public boolean alterMyNode(@PathVariable String item,@PathVariable String value,@PathVariable Integer nodeId,
                           HttpServletRequest request){
        QueryWrapper<Node> nodeQueryWrapper = new QueryWrapper<>();
        nodeQueryWrapper.eq("id",nodeId);
        Node node_origin = nodeService.getOne(nodeQueryWrapper);
        //找到原来的文件得到原来文件的位置
        String oldPath = request.getServletContext().getRealPath("/upload/"+ node_origin.getUserId() + "/" + node_origin.getClassName() + "/" + node_origin.getLanguage() + "/");
        String newPath = new String(); // 新路径
        String newNodename = node_origin.getNodename(); // 新的笔记名
        // 若改的是笔记类型
        if (item.equals("className")) {
            newPath = request.getServletContext().getRealPath("/upload/"+ node_origin.getUserId() + "/" + value + "/" + node_origin.getLanguage() + "/");
            // 修改数据
            node_origin.setClassName(value);
        }
        // 若改的是笔记语言
        if (item.equals("language")) {
            newPath = request.getServletContext().getRealPath("/upload/"+ node_origin.getUserId() + "/" + node_origin.getClassName() + "/" + value + "/");
            // 修改数据
            node_origin.setLanguage(value);
        }
        System.out.println("笔记路径：" + oldPath + "->" + newPath );
        //1.复制文件到修改的目录
        //创建文件对象
        File file_old = new File(oldPath + File.separator + node_origin.getNodename()+".md");
        File file = new File(newPath+ File.separator);
        File file_new = new File(newPath + File.separator + newNodename +".md");
        //若保存文件的地址不存在，则创建目录
        if(!file.exists()) {
            file.mkdirs();
        }
        try {
            System.out.println("复制笔记文件：" + file_old + "->" + file_new);
            copyFileUsingStream(file_old,file_new);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //2.删除原来的文件，并删除该笔记的数据库数据
        System.out.println("删除原文件");
        deleteMyNode(node_origin.getId(),request);
        System.out.println("更新数据库");
        // 向数据库添加新数据
        return nodeService.save(node_origin);
    }
    // 复制笔记文件
    private static void copyFileUsingStream(File source, File dest) throws IOException {
        InputStream is = null;
        OutputStream os = null;
        try {
            is = new FileInputStream(source);
            os = new FileOutputStream(dest);
            System.out.println(is);
            System.out.println(os);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = is.read(buffer)) > 0) {
                os.write(buffer, 0, length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            is.close();
            os.close();
        }
    }

}
